/*
 * EGSE.cpp
 *
 *  Created on: 03.06.2011
 *      Author: user
 */

#include "SatelliteInterface.h"
#include "worker-monitor-topics.h"
#include <vector>
#include <algorithm>

//Initialization of static const variables
const int SatelliteInterface::maxPing = 2;

//Constructor. Subscribes to the nmx topic using the SatelliteBuffer
SatelliteInterface::SatelliteInterface():SatelliteSubscriber(nmx,SatelliteBuffer) {}


int SatelliteInterface::getNumNodes(){
	//Returns the size of the node id list stored in this class
	return nodelist.size();
}

int SatelliteInterface::getNumUnresponsiveNodes(){
	//Store current number of nodes
	int size = nodelist.size();
	//Counter for counting the unresponsive nodes
	int count = 0;

	//Iterates through the node list and increment counter for every unresponsive node
	for(int i = 0;i<size;i++){
		if(nodelist[i].second >= maxPing){
			count++;
		}
	}
	//Return the number of unresponsive nodes
	return count;
}


int SatelliteInterface::getNumResponsiveNodes() {
	//Store current number of nodes
	int size = nodelist.size();
	//Counter for counting the responsive nodes
	int count = 0;

	//Iterate through the list of nodes and increment counter for every responsive node
	for(int i = 0;i<size;i++){
		if(nodelist[i].second <= maxPing){
			count++;
		}
	}
	//Return the number of responsive nodes
	return count;
}


int* SatelliteInterface::getUnresponsiveNodes(){
	//Get size of resulting array
	int size = getNumUnresponsiveNodes();
	//Create array
	int* result = new int[size];

	//Iterate through list of nodes and add ever unresponsive node to the array
	for(int i = 0, count = 0; i<nodelist.size(); i++){
		if(nodelist[i].second >= maxPing){
			result[count] = nodelist[i].first;
			count++;
		}
	}
	//return the pointer to the array holding the unresponsive nodes
	return result;
}


int* SatelliteInterface::getResponsiveNodes(){
	//Get size of resulting array
	int size = getNumResponsiveNodes();
	//If count != size after adding the nodes, values changed. return Zero-Pointer
	int count = 0;
	//Create array
	int* result = new int[size];

	//Iterate through list of nodes and add every responsive node to the array
	for(int i = 0; i<nodelist.size(); ++i){
		if(nodelist[i].second <= maxPing){
			result[count] = nodelist[i].first;
			++count;
		}
	}

	//return the pointer to the array holding the responsive nodes
	return result;
}


int* SatelliteInterface::getNodeIDList(){
	//Get size of resulting array
	int size = nodelist.size();
	//Create array
	int* result = new int[size];

	//Iterate through the list of nodes and add every node to the array
	for(int i = 0;i<size;i++) {
    		result[i] =  nodelist[i].first;
    }
	//return the pointer to the array holding the nodes
	return result;
}

bool SatelliteInterface::existNode(int ID){
	//Iterate through list of nodes. Return true when finding an active node with the given ID
	for(int i = 0; i<nodelist.size(); ++i){
		if(nodelist[i].first==ID && nodelist[i].second <= maxPing)
			return true;
	}

	//return false if there was no active node found with the given ID
	return false;
}

int SatelliteInterface::getWorkerID(){
	return WorkerID;
}


void SatelliteInterface::setWorker(int ID){
	//Prepares the message
	WMMessage output = {SET_WORKER,ID,1};

	nmx.publish(output);
}


void SatelliteInterface::setMonitor(int ID){
	//Prepares a SET_MONITOR message and sends it
	WMMessage output = {SET_MONITOR,ID,1};
	nmx.publish(output);
}


operationMode SatelliteInterface::getMode(){
	//Returns the mode of operation
	return oMode;
}


void SatelliteInterface::setMode(operationMode mode){
	//Prepares a SET_MODE message and sends it
	WMMessage output = {SET_MODE,-1,-1};
	nmx.publish(output);
}


void SatelliteInterface::Ping(){
	//Prepares a Ping message and sends it
	WMMessage output = {PING,-1,-1};
	nmx.publish(output);

	//Increment the ping counter for every node
	for(int i = 0; i < nodelist.size(); ++i) {
		++(nodelist[i].second);
	}
}


void SatelliteInterface::WorkerPing(){
	//Prepares and sends a message to identify the worker
	WMMessage output = {IDENTIFY_WORKER,-1,-1};
	nmx.publish(output);
}

void SatelliteInterface::handleMessages(){
	//Variable to hold a topic read from the buffer
	WMMessage topicInput = {MEANINGLESS,-1,-1};

	//while the message buffer is not empty we do the following for every message
	while(SatelliteBuffer.get(topicInput)){

		//if the message is a message of type PONG
		if(topicInput.messageType == PONG){
			//get size of node list
			int size = ( nodelist.size());
			int pos = 0;

			//Tries to find an entry with the given nodeID
			for(; pos < size && nodelist[pos].first != topicInput.nodeNumber; ++pos);

			if (pos != size){
				//if the node was found in the node list note that it's responsive
				nodelist[pos].second = 0;
			}
			else {
				//if it wasn't found, add it to the list
				nodelist.push_back(std::pair<int,int>(topicInput.nodeNumber,0));
			}
		}

		//if the message is of type IDENTIFY_WORKER and it's not a requesting message
		if(topicInput.messageType == IDENTIFY_WORKER && topicInput.nodeNumber != -1){
			//note the new worker id
			WorkerID = topicInput.nodeNumber;
		}
	}
}


void SatelliteInterface::setPublishPeriod(long  time) {
	//Prepares and publishes the SET_STATUS_PERIOD message
	WMMessage msg = {SET_STATUS_PERIOD,-1,time};
	nmx.publish(msg);
}

void SatelliteInterface::setPublishStatusData(bool send) {
	WMMessage msg = {SET_STATUS_SEND,-1, (send ? 1 : 0)};
	nmx.publish(msg,true);
}

void SatelliteInterface::updateSatellite() {
	//Ping all nodes
	Ping();
	//Identify the worker
	WorkerPing();
	//handle all messages
	handleMessages();
}

void SatelliteInterface::init() {
	//Set up periodic beat
	this->setPeriodicBeat(NOW()+1*SECONDS,1*SECONDS);
}

void SatelliteInterface::run() {
	//Update satellite data forever once per beat
	while(1) {
		updateSatellite();
		waitUntilNextBeat();
	}
}

